//--------------------------------------------------------------------------------------
// File: MandelShader.cpp
//
// Empty starting point for new Direct3D 9 and/or Direct3D 11 applications
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include "DXUT.h"
#include "Application.h"
#include "FrameworkAdapter.h"
#include <memory>

//--------------------------------------------------------------------------------------
// Reject any D3D11 devices that aren't acceptable by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsD3D11DeviceAcceptable( const CD3D11EnumAdapterInfo *AdapterInfo, UINT Output, const CD3D11EnumDeviceInfo *DeviceInfo,
                                       DXGI_FORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
{
    return static_cast<MandelShader::IApplication *>(pUserContext)->IsDeviceAcceptable(AdapterInfo, Output, DeviceInfo, BackBufferFormat, bWindowed);
}


//--------------------------------------------------------------------------------------
// Called right before creating a D3D9 or D3D11 device, allowing the app to modify the device settings as needed
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{
    return static_cast<MandelShader::IApplication *>(pUserContext)->ModifyDeviceSettings(pDeviceSettings);
}


//--------------------------------------------------------------------------------------
// Create any D3D11 resources that aren't dependent on the back buffer
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D11CreateDevice( ID3D11Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc,
                                      void* pUserContext )
{
	return static_cast<MandelShader::IApplication *>(pUserContext)->OnCreateDevice(pd3dDevice, pBackBufferSurfaceDesc);
}


//--------------------------------------------------------------------------------------
// Create any D3D11 resources that depend on the back buffer
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D11ResizedSwapChain( ID3D11Device* pd3dDevice, IDXGISwapChain* pSwapChain,
                                          const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
{
    return static_cast<MandelShader::IApplication *>(pUserContext)->OnResizedSwapChain(pd3dDevice, pSwapChain, pBackBufferSurfaceDesc);
}


//--------------------------------------------------------------------------------------
// Handle updates to the scene.  This is called regardless of which D3D API is used
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
{
	return static_cast<MandelShader::IApplication *>(pUserContext)->OnFrameMove(fTime, fElapsedTime);
}


//--------------------------------------------------------------------------------------
// Render the scene using the D3D11 device
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D11FrameRender( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext,
                                  double fTime, float fElapsedTime, void* pUserContext )
{
	static_cast<MandelShader::IApplication *>(pUserContext)->OnFrameRender(pd3dDevice, pd3dImmediateContext, fTime, fElapsedTime);
}


//--------------------------------------------------------------------------------------
// Release D3D11 resources created in OnD3D11ResizedSwapChain 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D11ReleasingSwapChain( void* pUserContext )
{
	static_cast<MandelShader::IApplication *>(pUserContext)->OnReleasingSwapChain();
}


//--------------------------------------------------------------------------------------
// Release D3D11 resources created in OnD3D11CreateDevice 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D11DestroyDevice( void* pUserContext )
{
	static_cast<MandelShader::IApplication *>(pUserContext)->OnDestroyDevice();
}


//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                          bool* pbNoFurtherProcessing, void* pUserContext )
{
	return static_cast<MandelShader::IApplication *>(pUserContext)->MsgProc(hWnd, uMsg, wParam, lParam, pbNoFurtherProcessing);
}


//--------------------------------------------------------------------------------------
// Handle key presses
//--------------------------------------------------------------------------------------
void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext )
{
	static_cast<MandelShader::IApplication *>(pUserContext)->OnKeyboard(nChar, bKeyDown, bAltDown);
}


//--------------------------------------------------------------------------------------
// Handle mouse button presses
//--------------------------------------------------------------------------------------
void CALLBACK OnMouse( bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown,
                       bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta,
                       int xPos, int yPos, void* pUserContext )
{
	static_cast<MandelShader::IApplication *>(pUserContext)->OnMouse(
		bLeftButtonDown, bRightButtonDown, bMiddleButtonDown,
		bSideButton1Down, bSideButton2Down, nMouseWheelDelta,
		xPos, yPos);
}


//--------------------------------------------------------------------------------------
// Call if device was removed.  Return true to find a new device, false to quit
//--------------------------------------------------------------------------------------
bool CALLBACK OnDeviceRemoved( void* pUserContext )
{
    return static_cast<MandelShader::IApplication *>(pUserContext)->OnDeviceRemoved();
}


//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
	using namespace MandelShader;
	FrameworkAdapter adapter;
	std::auto_ptr<IApplication> app(CreateApplication(&adapter));

    // Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

    // DXUT will create and use the best device (either D3D9 or D3D11) 
    // that is available on the system depending on which D3D callbacks are set below

    // Set general DXUT callbacks
    DXUTSetCallbackFrameMove( OnFrameMove, app.get() );
    DXUTSetCallbackKeyboard( OnKeyboard, app.get() );
    DXUTSetCallbackMouse( OnMouse, false, app.get() );
    DXUTSetCallbackMsgProc( MsgProc, app.get() );
    DXUTSetCallbackDeviceChanging( ModifyDeviceSettings, app.get() );
    DXUTSetCallbackDeviceRemoved( OnDeviceRemoved, app.get() );

    // Set the D3D11 DXUT callbacks. Remove these sets if the app doesn't need to support D3D11
    DXUTSetCallbackD3D11DeviceAcceptable( IsD3D11DeviceAcceptable, app.get() );
    DXUTSetCallbackD3D11DeviceCreated( OnD3D11CreateDevice, app.get() );
    DXUTSetCallbackD3D11SwapChainResized( OnD3D11ResizedSwapChain, app.get() );
    DXUTSetCallbackD3D11FrameRender( OnD3D11FrameRender, app.get() );
    DXUTSetCallbackD3D11SwapChainReleasing( OnD3D11ReleasingSwapChain, app.get() );
    DXUTSetCallbackD3D11DeviceDestroyed( OnD3D11DestroyDevice, app.get() );

    // Perform any application-level initialization here
	app->Startup();

    DXUTInit( true, true, NULL ); // Parse the command line, show msgboxes on error, no extra command line params
    DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
    DXUTCreateWindow( L"MandelShader" );

    // Only require 10-level hardware
    DXUTCreateDevice( D3D_FEATURE_LEVEL_10_0, true, 640, 480 );
    DXUTMainLoop(); // Enter into the DXUT render loop

    // Perform any application-level cleanup here
	app->Shutdown();

	DXUTShutdown(0);
	return DXUTGetExitCode();
}


